﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using ADV_Evaluator; 
using ADV_Evaluator.Data;
using ADV_Evaluator.Command;


namespace ADV_Editor.CommandDialog {

    /// <summary>
    /// 「変数の操作」コマンドのダイアログ
    /// </summary>
    partial class VariableDialog : CommandDialogBase {

        /// <summary>
        /// 何も表示しない状態からはじめるコンストラクタ
        /// </summary>
        public VariableDialog() {
            InitializeComponent();
            comboBox.Items.Add(VariableOperation.代入);
            comboBox.Items.Add(VariableOperation.加算);
            comboBox.Items.Add(VariableOperation.減算);
            comboBox.Items.Add(VariableOperation.乗算);
            comboBox.Items.Add(VariableOperation.除算);
            comboBox.Items.Add(VariableOperation.剰余);
            comboBox.Items.Add(VariableOperation.累乗);
            comboBox.SelectedIndex = 0;
        }

        /// <summary>
        /// 初期値を指定したコンストラクタ
        /// </summary>
        /// <param name="param">属性</param>
        public VariableDialog(VariableParams param) : this(){
            textBox_VarName.Text = param.Name;
            comboBox.SelectedItem = param.Operation;
            switch (param.OperandType) {
            case VariableOperand.定数:
                radioButton_Const.Checked = true;
                numericUpDown_Operand_Const.Value = (short)param.OperandValue;
                break;
            case VariableOperand.変数:
                radioButton_Variable.Checked = true;
                textBox_Operand_VarName.Text = (string)param.OperandValue;
                break;
            case VariableOperand.乱数:
                radioButton_Random.Checked = true;
                short[] range = (short[])param.OperandValue;
                numericUpDown_Operand_Rand1.Value = range[0];
                numericUpDown_Operand_Rand2.Value = range[1];
                break;
            }
        }

        /// <summary>
        /// 変数名の欄に何か入力されたとき
        /// </summary>
        private void textBox_TextChanged(object sender, EventArgs e) {
            // 未入力ならOKを押させない
            LockOKButton();
        }

        /// <summary>
        /// 演算子の値が変化したとき
        /// </summary>
        private void comboBox_SelectedIndexChanged(object sender, EventArgs e) {
            LockOKButton();
        }

        /// <summary>
        /// オペランドの値が変化したとき
        /// </summary>
        private void numericUpDown_ValueChanged(object sender, EventArgs e) {
            LockOKButton();
        }

        /// <summary>
        /// 条件を満たしたときだけOKボタンが押せるようにする
        /// </summary>
        private void LockOKButton() {
            // 変数名は必須
            if (textBox_VarName.Text.Length == 0) {
                button_OK.Enabled = false;
            } else if (radioButton_Variable.Checked && textBox_Operand_VarName.Text.Length == 0) {
                button_OK.Enabled = false;
            // 0の除算は認めない
            } else if ((VariableOperation)comboBox.SelectedItem == VariableOperation.除算 && radioButton_Const.Checked && numericUpDown_Operand_Const.Value == 0) {
                button_OK.Enabled = false;
            // マイナスの累乗は認めない
            } else if ((VariableOperation)comboBox.SelectedItem == VariableOperation.累乗 && radioButton_Const.Checked && numericUpDown_Operand_Const.Value < 0) {
                button_OK.Enabled = false;
            // 先頭に数字とか記号文字はダメ
            } else if (!Regex.IsMatch(textBox_VarName.Text, @"^[^0-9\s\,\.\/\<\>\?\;\:\]\+\*\}\@\[\`\{\-\^\\\!\\""\#\$\%\&\'\(\)\=\~\|]\w*", RegexOptions.Compiled)) {
                button_OK.Enabled = false;
            } else if (radioButton_Variable.Checked && !Regex.IsMatch(textBox_Operand_VarName.Text, @"^[^0-9\s\,\.\/\<\>\?\;\:\]\+\*\}\@\[\`\{\-\^\\\!\\""\#\$\%\&\'\(\)\=\~\|]\w*", RegexOptions.Compiled)) {
                button_OK.Enabled = false;
            } else {
                button_OK.Enabled = true;
            }
        }

        /// <summary>
        /// オペランドラジオボタンの状態が変化したとき
        /// </summary>
        private void radioButton_Operand_CheckedChanged(object sender, EventArgs e) {
            LockOKButton();
            numericUpDown_Operand_Const.Enabled = false;
            textBox_Operand_VarName.Enabled = false;
            numericUpDown_Operand_Rand1.Enabled = false;
            numericUpDown_Operand_Rand2.Enabled = false;
            if (radioButton_Const.Checked) {
                numericUpDown_Operand_Const.Enabled = true;
            } else if (radioButton_Variable.Checked) {
                textBox_Operand_VarName.Enabled = true;
            } else if (radioButton_Random.Checked) {
                numericUpDown_Operand_Rand1.Enabled = true;
                numericUpDown_Operand_Rand2.Enabled = true;
            }
        }

        /// <summary>
        /// テキストボックスに文字が入力されるとき
        /// </summary>
        private void textBox_KeyPress(object sender, KeyPressEventArgs e) {
            // 空白文字とか記号文字は不可
            foreach (char c in Const.InvalidVariableChars) {
                if (e.KeyChar == c) {
                    e.Handled = true;
                    break;
                }
            }
        }
        
        /// <summary>
        /// 入力されたデータをコマンド化したもの
        /// </summary>
        public override CommandListData Command {
            get {
                VariableParams param = new VariableParams();
                param.Name = textBox_VarName.Text;
                param.Operation = (VariableOperation)comboBox.SelectedItem;
                param.OperandType = radioButton_Const.Checked ? VariableOperand.定数 : radioButton_Variable.Checked ? VariableOperand.変数 : VariableOperand.乱数;
                switch (param.OperandType) {
                case VariableOperand.定数:
                    param.OperandValue = (short)numericUpDown_Operand_Const.Value;
                    break;
                case VariableOperand.変数:
                    param.OperandValue = textBox_Operand_VarName.Text;
                    break;
                case VariableOperand.乱数:
                    param.OperandValue = new short[2] { (short)numericUpDown_Operand_Rand1.Value, (short)numericUpDown_Operand_Rand2.Value };
                    break;
                }
                return new CommandListData(CommandName.変数の操作, param);
            }
        }

        #region ヘルプ
        /// <summary>
        /// OKボタンのヘルプ
        /// </summary>
        private void button_OK_HelpRequested(object sender, HelpEventArgs hlpevent) {
            ShowPopupHelp(sender, "このダイアログを閉じて、コマンドを追加します。");
        }
        /// <summary>
        /// キャンセルボタンのヘルプ
        /// </summary>
        private void button_Cancel_HelpRequested(object sender, HelpEventArgs hlpevent) {
            ShowPopupHelp(sender, "変更内容を保存せずにこのダイアログを閉じます。");
        }
        /// <summary>
        /// 変数名のヘルプ
        /// </summary>
        private void textBox_HelpRequested(object sender, HelpEventArgs hlpevent) {
            ShowPopupHelp(sender, "操作する変数名を入力します。\n変数名は全角文字でも構いません。\n未定義の変数は0と看做されます。");
        }
        /// <summary>
        /// 演算のヘルプ
        /// </summary>
        private void comboBox_HelpRequested(object sender, HelpEventArgs hlpevent) {
            ShowPopupHelp(sender, "変数に対する演算を指定します。");
        }
        /// <summary>
        /// オペランドのヘルプ
        /// </summary>
        private void groupBox_Operand_HelpRequested(object sender, HelpEventArgs hlpevent) {
            ShowPopupHelp(sender, "演算の対象となる値を指定します。");
        }
        #endregion




    }
}